package sunwul.datasource.db;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import sunwul.datasource.emun.DatabaseOperation;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/*****
 * @author sunwul
 * @date 2022/2/21 16:20
 * @description 动态数据源
 * 继承AbstractRoutingDataSource抽象类
 *      - 重写determineCurrentLookupKey()方法, 返回当前数据源标识
 *      - 重写afterPropertiesSet()方法, 在Bean初始化时装载配置[设置数据源列表,默认数据源], 调用父类方法, 使配置生效
 *
 * 此方法继承了Spring框架的抽象类, 只需要重写determineCurrentLookupKey()与afterPropertiesSet()方法
 * 其它方法使用Spring的默认实现, 与Spring框架更契合
 */
@Component
@Primary  // 作为主要注入Bean, 当出现相同类型的Bean时,会使用含此注解的Bean
public class DynamicDatasource extends AbstractRoutingDataSource {

    // 当前使用的数据源标识  线程安全(多线程对这个name进行同时读写时,会出现单独或篡改的情况)
    public static ThreadLocal<String> name = new ThreadLocal<>();

    // 写
    @Autowired
    DataSource dataSource_write;

    // 读
    @Autowired
    DataSource dataSource_read;

    /**
     * 返回当前数据源标识
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return name.get();
    }

    /**
     * 初始化设置
     * 1. 设置数据源列表
     * 2. 设置默认的数据源
     * 3. 调用父类的afterPropertiesSet方法, 使设置生效
     * (具体可以查看父类afterPropertiesSet方法,可以看到此方法中判断了数据源列表[必要,否则会异常]和默认数据源[非必要])
     */
    @Override
    public void afterPropertiesSet() {
        // 所有数据源Map   将数据源标识与数据源put进来
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseOperation.Write.getName(), dataSource_write);
        targetDataSources.put(DatabaseOperation.Read.getName(), dataSource_read);

        System.out.println("===================初始化数据源列表===================");
        // targetDataSources 初始化所有数据源
        super.setTargetDataSources(targetDataSources);

        System.out.println("===================设置默认数据源===================");
        // defaultTargetDataSource 设置默认的数据源
        super.setDefaultTargetDataSource(dataSource_write);

        // 调用父类的 afterPropertiesSet 方法, 使设置生效
        super.afterPropertiesSet();
    }
}
